package lib.json;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class JSONUnserializer
{
	private int pointer;
	private String json;
	
	public JSONUnserializer()
	{
	}
	
	public Object unserialize(String _json) throws Exception
	{
		json = _json;
		pointer = 0;
		
		return _getAttributeValue();
	}
	
	private String _getAttributeKey() throws Exception
	{
		// get start
		int start = -1;
		for (int i=pointer; i<json.length(); i++)
		{
			if (json.charAt(i) == '"')
			{
				start = i;
				break;
			} else if (
				json.charAt(i) == '}' ||
				json.charAt(i) == ']' ||
				json.charAt(i) == '{' ||
				json.charAt(i) == '['
			) {
				// closing tag or opening tag
				return null;
			}
		}
		if (start == -1) return null;
		pointer = start +1;
		
		String key;
		key = _getString();
		
		pointer = json.indexOf(':', pointer) +1;
		return key;
	}
	
	private Object _getAttributeValue() throws Exception
	{
		while (
			json.charAt(pointer) == ' ' ||
			json.charAt(pointer) == ',' ||
			json.charAt(pointer) == '\n' ||
			json.charAt(pointer) == '\t'
		) pointer++;
		
		if (json.charAt(pointer) == '{')
		{
			// object
			pointer++;
			return _getObject();
		} else if (json.charAt(pointer) == '[')
		{
			// array
			pointer++;
			return _getArray();
		} else if (json.charAt(pointer) == '"')
		{
			// string
			pointer++;
			return _getString();
		} else if (json.charAt(pointer) == 't' || json.charAt(pointer) == 'f')
		{
			// boolean
			return _getBoolean();
		} else if (_isNum(json.charAt(pointer)))
		{
			// integer/float
			return _getNumber();
		}
		
		return null;
	}

	/*
	 * get Value - supported Types [Object, Array, String, Boolean, Integer]
	 */
	
	private String _getString() throws Exception
	{
		int start = pointer;
		int end = json.indexOf('"', start);
		if (end == -1)
		{
			throw new Exception("JSONUnserializer Error: No end found for string");
		}
		pointer = end +1;
		return json.substring(start, end);
	}
	
	private Map<String, Object> _getObject() throws Exception
	{
		Map<String, Object> data = new HashMap<String, Object>();
		
		String key;
		while ((key = _getAttributeKey()) != null)
		{
			Object value = _getAttributeValue();
			data.put(key, value);
		}
		
		pointer = json.indexOf('}', pointer) +1;
		
		return data;
	}
	
	private ArrayList<Object> _getArray() throws Exception
	{
		ArrayList<Object> data = new ArrayList<Object>();
		
		Object value;
		while ((value = _getAttributeValue()) != null)
		{
			data.add(value);
		}
		
		pointer = json.indexOf(']', pointer) +1;
		
		return data;
	}
	
	private Boolean _getBoolean()
	{
		if (json.charAt(pointer) == 't')
		{
			pointer+= 4;
			return new Boolean(true);
		} else
		{
			pointer+= 4;
			return new Boolean(false);
		}
	}
	
	private Object _getNumber()
	{
		String s = "";
		while (_isNum(json.charAt(pointer)))
		{
			s+= json.charAt(pointer);
			pointer++;
		}
		if (s.indexOf('.') != -1)
		{
			return Float.parseFloat(s);
		} else
		{
			return Integer.parseInt(s);
		}
	}
	
	private boolean _isNum(char x)
	{
		if (
			x == '-' || x == '0' ||
			x == '1' || x == '2' ||
			x == '3' || x == '4' ||
			x == '5' || x == '6' ||
			x == '7' || x == '8' ||
			x == '9' || x == '.'
		) return true;
		return false;
	}
}
